package com.base.monitor.module.biz.handler;

import cn.hutool.core.collection.CollectionUtil;
import com.base.monitor.model.model.biz.cfg.entity.Gateway;
import com.base.monitor.module.biz.context.CfgContext;
import com.base.monitor.module.biz.context.ClientContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 这个handler是用于剔除离线的连接
 * 现阶段剔除的标准是3倍网关心跳时间。在这个时间内都没有收到心跳，那么就直接剔除了
 */
@Component
@Slf4j
public class RemoveOfflineChannelHandler implements InitializingBean {

    @Value("${cfg.gatewayTimeout}")
    private String gatewayTimeout;

    @Override
    public void afterPropertiesSet() throws Exception {
        ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(2);
        scheduledExecutorService.scheduleWithFixedDelay(new RemoveOfflineChannelTask(), 20, 30, TimeUnit.SECONDS);
    }

    private class RemoveOfflineChannelTask implements Runnable {
        @Override
        public void run() {
            log.info("开始检查离线的连接并进行剔除完成");
            List<ClientContext.ChannelInfo> channelInfos = new ArrayList<>(ClientContext.getClientMap().values());
            if (CollectionUtil.isEmpty(channelInfos)) {
                return;
            }
            List<ClientContext.ChannelInfo> offlineCtxList = new ArrayList<>();
            for (ClientContext.ChannelInfo channelInfo : channelInfos) {
                Gateway gateway = CfgContext.getGatewayVoByCommand(channelInfo.getCommand());
                if (gateway == null) {
                    continue;
                }
                Date onlineTime = CfgContext.getGatewayOnlineMap().get(gateway.getGatewayId());
                if (onlineTime == null
                        || System.currentTimeMillis() - onlineTime.getTime() >= Integer.parseInt(gatewayTimeout) * 1000) {
                    offlineCtxList.add(channelInfo);
                }
            }

            if (CollectionUtil.isEmpty(offlineCtxList)) {
                log.info("检查离线的连接并进行剔除完成，本次没有离线的信道需要剔除");
                return;
            }
            for (ClientContext.ChannelInfo channelInfo : offlineCtxList) {
                // 关闭信道
                channelInfo.getCtx().close();
                // 从clientMap中剔除
                ClientContext.removeClient(channelInfo.getCtx());
            }

            log.info("检查离线的连接并进行剔除完成，本次因为离线而剔除的信道对应的连接命令为:{}",
                    offlineCtxList.stream().map(ClientContext.ChannelInfo::getCommand).collect(Collectors.toList()));
        }
    }
}
